import datetime

import bcrypt
import simplejson

from .send_email import sendmail
from utils import jsonify, get_token
from todolist.settings import redis_db0, redis_db3
from .models import user_manger, User, ip_manger, IP

from django.db.models import Q
from django.db import transaction
from django.http import HttpRequest, JsonResponse
from django.views.decorators.http import require_POST


def send_email_async(user, timeout=40):
    token = get_token(user)
    redis_db3.setex(user.name, datetime.timedelta(seconds=timeout), token)
    sendmail.delay(user.name, user.email, token)


@require_POST
def reg(request: HttpRequest):
    try:
        payload = simplejson.loads(request.body)
        # TODO 此处可能会出现问题，ip有可能会不对
        remote_ip = request.META.get('REMOTE_ADDR')
        name = payload['name']
        email = payload['email']

        # 先在redis的ip池里判断当前ip是否已经存在，如果存在，返回当前ip已经被注册，请求结束
        is_exist = redis_db0.sismember('ips', remote_ip)
        if is_exist:
            # 当前IP已经被注册
            return JsonResponse({"error": "ip had reg"}, status=400)

        # 在redis中的name池里判断用户名是否已经存在，email是否已经存在，如果存在，则返回，请求结束
        is_exist = redis_db0.sismember('name', name) or redis_db0.sismember('email', email)
        if is_exist:
            return JsonResponse({'error': "already exists"}, status=400)

        # 使用mysql查询，判断用户是否被注册，双重保险，如果ip已经存在，或者name已经存在，或者email已经存在，则返回，请求结束
        user = user_manger.filter(Q(name=name) | Q(email=email) | Q(log_ip=remote_ip))
        ip = ip_manger.filter(ip=remote_ip)
        if user or ip:
            return JsonResponse({'error': "already exists"}, status=400)

        # 当前用户可以被注册，以下是用户正常注册的代码
        # 对密码进行加密，最终以字符串形式出现
        password = bcrypt.hashpw(payload['password'].encode(), bcrypt.gensalt()).decode()

        # 运用orm创建一个用户对象，将用户信息分别存储到mysql跟redis中
        user = User(name=name, email=email, password=password, log_ip=remote_ip)
        with transaction.atomic():

            # 将新注册的ip存入到redis中
            redis_db0.sadd('ips', remote_ip)
            redis_db0.sadd('name', name)
            redis_db0.sadd('email', email)
            print(name, remote_ip, email)
            data = {
                'ip': remote_ip,
                'email': email,
                'is_active': 0,
            }
            # val = json.dumps(data)
            # print(val)
            redis_db0.hmset(name, data)

            ip = IP(ip=remote_ip)
            ip.save()
            user.save()
        # 用户信息已经存储完毕，然后给用户发送激活邮件
        send_email_async(user, 40)
        # token = get_token(user)
        # redis_db3.setex(user.name, datetime.timedelta(seconds=40), token)
        # # redis_db3.hset("users", user.name, token)
        # sendmail.delay(user.name, user.email, token)

        return JsonResponse({'user': jsonify(user, exclude="password")}, status=201)

    except Exception as e:
        print(e, '=======')
        return JsonResponse({"error": "input error"}, status=400)


@require_POST
def login(request: HttpRequest):
    try:
        payload = simplejson.loads(request.body)
        # 用户名或者邮箱都使用name字段进行数据的提交
        name = payload.get('name')
        password = payload['password']
        u = redis_db0.hget(name, 'is_active')

        # 在redis中，判断用户是否已经被激活，如果未被激活，则直接返回，请求结束
        if not u:
            return JsonResponse({"error": "need to active account"}, status=401)

        user = user_manger.filter(Q(name=name) | Q(email=name))

        if len(user) != 1:
            return JsonResponse({"error": "username or password error"}, status=401)

        user = user[0]

        if not user.is_active:
            return JsonResponse({"error": "need to active account"}, status=401)

        if bcrypt.checkpw(password.encode(), user.password.encode()):
            payload = jsonify(user, exclude='password')
            token = get_token(user)
            return JsonResponse(
                {'user': {
                    'info': payload,
                    'token': token
                }
                })

    except Exception as e:
        print(e, '----------')

    return JsonResponse({'error': "username or password error"}, status=401)


def active(request: HttpRequest):
    try:
        # 从url中获取到用户的相关信息
        username = request.GET.get('username')
        token = request.GET.get('token')

        # 在redis中判断用户是否存在，如果不存在则直接返回，请求结束
        is_exits = redis_db0.sismember('name', username)
        if not is_exits:
            return JsonResponse({"error": "illegal user"}, status=400)

        # 判断当前用户是否在过期期限内，如果在，则给予激活，否则，过期的相关操作
        tk = redis_db3.get(username)
        if tk:
            user = user_manger.filter(name=username)[0]

            if tk.decode() == token:
                redis_db3.delete(username)
                redis_db0.hset(username, 'is_active', 1)
                user.is_active = 1
                user.save()

                return JsonResponse({"ok": "success active current account"}, status=200)

            return JsonResponse({"error": "token error"}, status=401)
        else:
            user = user_manger.filter(name=username)[0]
            # 用户已经成功注册~
            if redis_db0.hget(username, 'is_active'):
                return JsonResponse({"ok": "already reg, don't re reg"})

            # TODO 是否进行重新激活的操作，此处直接进行重新邮件的发送，让用户激活
            # 过期了
            send_email_async(user, 40)
            return JsonResponse({"error": "exp user"}, status=405)

    except Exception as e:
        print(e, '----------')
        return JsonResponse({"error": "fail to active current account"}, status=400)
